package org.ndx.jsg.guice;

import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

/**
 * Creates a class loader that will load all classes from all jars in the given
 * directories
 * 
 * @author ndx
 * 
 */
public class ClassLoaderHelper {
	/**
	 * Build a class loader including all jars from all directories
	 * 
	 * @see #buildClassLoader(List, boolean, ClassLoader)
	 * @param directories
	 * @param includeSubDirs
	 * @return
	 */
	static ClassLoader buildClassLoader(List<File> directories,
			boolean includeSubDirs) {
		return buildClassLoader(directories, includeSubDirs, Thread
				.currentThread().getContextClassLoader());
	}

	/**
	 * Build a class loader including all jars from all given directories, using
	 * as parent the given one
	 * 
	 * @param directories
	 * @param includeSubDirs
	 * @param parent
	 * @return
	 */
	static ClassLoader buildClassLoader(List<File> directories,
			boolean includeSubDirs, ClassLoader parent) {
		List<URL> allJars = new ArrayList<URL>();
		// Find all Jars in each directory
		for (File dir : directories) {
			fillJarsList(allJars, dir, includeSubDirs);
		}
		return new URLClassLoader(allJars.toArray(new URL[allJars.size()]),
				parent);
	}

	/**
	 * Find all ajrs from all directories and add them to the list of usable
	 * jars
	 * 
	 * @param jars
	 * @param dir
	 * @param includeSubDirs
	 */
	static private void fillJarsList(List<URL> jars, File dir,
			boolean includeSubDirs) {
		try {
			for (File jar : dir.listFiles(_jarsFilter)) {
				jars.add(jar.toURI().toURL());
			}

			if (includeSubDirs) {
				for (File subdir : dir.listFiles(_dirsFilter)) {
					fillJarsList(jars, subdir, true);
				}
			}
		} catch (Exception e) {
			// Should not happen
		}
	}

	static final private FileFilter _jarsFilter = new FileFilter() {

		@Override
		public boolean accept(File pathname) {
			return pathname.getName().endsWith(".jar");
		}
	};

	static final private FileFilter _dirsFilter = new FileFilter() {

		@Override
		public boolean accept(File pathname) {
			return true;
		}
	};
}